//仿照Vue2的MVVM，实现简单的数据驱动
class MVVM {
    constructor(options){
        this._el = options.el;
        this._data = options.data;
        this._methods = options.methods;
        this.$el = this._template = document.querySelector(this._el);
        this.render();
    }
}

MVVM.prototype.render = function (){
    this.addMethods(this._methods);
    this.compiler( this._template );
}

MVVM.prototype.addMethods = function(){
    
}

/* ************ 更新页面 *********** */
MVVM.prototype.compiler = function( template ){
  //生成template的深度拷贝
  let generateTemplate = template.cloneNode( true );
  //调用compiler()函数
  compiler(generateTemplate, this._data,this._methods);
  //替换$el
  this.$el = generateTemplate;
  //更新页面Dom
  this.update( generateTemplate );
}

/* ************ 更新页面 *********** */
MVVM.prototype.update = function ( GTemplate ){
this._template.parentNode.replaceChild(GTemplate , this._template);
}

  function compiler( template, data,methods){
    let childNodes = template.childNodes; //获取模板内的子结点
    for (let i = 0; i < childNodes.length; i++){
      let type = childNodes[i].nodeType; //nodeType表示结点类型；返回值为3，代表文本结点，返回值为1，代表元素结点
      if(type === 3){
        let txt = childNodes[i].nodeValue;
        let regex_hks = /\{\{(.+?)\}\}/g; //g表示全局匹配
        txt = txt.replace( regex_hks , function ( _ ,g) { // replace()方法接受两个参数，一个是正则表达式，一个是匹配到结果后的处理函数
          let path = g.trim();                             // 其中第0个参数表示匹配到的内容，第n个参数表示匹配到的第n组
          let value = getDatabyPath(data,path);                          //每匹配到一个结果，该函数就会被调用，并返回一个替换该结果的值
          return value;                                   //全部替换完成，返回一个新的字符串
        });
        childNodes[i].nodeValue = txt;  // 修改节点的值
      }
      else if(type === 1){
        if(childNodes[i].hasAttribute('@click')){
          let path = childNodes[i].getAttribute('@click');
          // 去除括号的正则
          path = path.replace(/\(|\)/g,'');
          childNodes[i].onclick = methods[path]
        }
        compiler( childNodes[i], data); //如果不是文本结点，递归（使用递归保证了即便是层级的html结构依然可以找到文本结点）
      }
      // else{
      //   console.log(type);
      //   throw('暂不支持该节点类型')
      // }
    }
  }

  function getDatabyPath(data, path ) {
    let paths = path.trim().split(/\.|\[|\]/); //分割层级路径以及带有[]的路径
    let res = data;
    let prop;
    while( prop = paths.shift() ){ //从队首依次弹出数据
      if(prop === '') continue; //解决分割中出现 '' 的问题（分割[?]时会出现该问题）
      res = res[prop];
    }
    return res;
  }
  